package logger

import (
	"context"
	"log/slog"
	"runtime"
	"slices"
	"sync"
	"time"
	"unsafe"
)

// handlerAgent 控制器
type handlerAgent struct {
	options     *Options             // Handler选项
	logLevel    *slog.LevelVar       // slog.Handler日志级别
	logOpts     *slog.HandlerOptions // slog.Handler选项
	handler     slog.Handler         // slog.Handler处理器实例
	storage     Storager             // 日志存储器
	withAttrs   []slog.Attr          // 附加属性记录，用以支持中间件的属性追加支持
	middlewares []Middleware         // 中间件列表
	errorEvents []Event              // 错误事件回调列表
	closeEvents []Event              // 关闭事件回调列表
	lastErrors  *lastErrors          // 最近的错误信息
	mu          *sync.RWMutex
}

// Middleware 日志记录中间件, 返回不为nil的错误，终止后续中间件处理及丢弃此条日志的记录
type Middleware func(ctx *context.Context, record *slog.Record) error

// Event 事件回调函数, 用于处理日志记录过程中的错误信息或关闭操作
type Event func(error)

var _ slog.Handler = (*handlerAgent)(nil)

func newJsonHandler(s Storager, opts *Options) *handlerAgent {
	c := new(handlerAgent)
	c.storage = s
	c.initOptions(opts)
	c.handler = slog.NewJSONHandler(c.storage, c.logOpts)
	return c
}
func newTextHandler(s Storager, opts *Options) *handlerAgent {
	c := new(handlerAgent)
	c.storage = s
	c.initOptions(opts)
	c.handler = slog.NewTextHandler(c.storage, c.logOpts)
	return c
}
func (h *handlerAgent) initOptions(options *Options) {
	h.options = &Options{
		Level:       defaultLogLevel,
		AddSource:   defaultAddSource,
		CallerSkip:  defaultCallerSkip,
		ReplaceAttr: nil,
	}
	if options != nil {
		h.options.Level = options.Level
		h.options.AddSource = options.AddSource
		if options.CallerSkip > defaultCallerSkip {
			h.options.CallerSkip = options.CallerSkip
		}
		h.options.ReplaceAttr = options.ReplaceAttr
	}
	h.logLevel = &slog.LevelVar{}
	h.logLevel.Set(h.options.Level)
	h.logOpts = &slog.HandlerOptions{
		Level:     h.logLevel,
		AddSource: h.options.AddSource,
		ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
			if h.options.ReplaceAttr != nil {
				a = h.options.ReplaceAttr(groups, a)
			}
			if a.Key == slog.LevelKey {
				if level, ok := a.Value.Any().(slog.Level); ok {
					if name, exists := levelNames[level]; exists {
						a.Value = slog.StringValue(name)
					} else {
						a.Value = slog.StringValue(Level(level).String())
					}
				}
			}
			return a
		},
	}
	h.middlewares = nil
	h.errorEvents = nil
	h.closeEvents = nil
	h.lastErrors = &lastErrors{make([]error, 0, 10)}
	h.mu = new(sync.RWMutex)
}

// GetOptions 获取日志选项
func (h *handlerAgent) GetOptions() Options {
	return *h.options
}

// OnClose 注册关闭事件处理器
func (h *handlerAgent) OnClose(fn Event) {
	if fn == nil {
		return
	}
	h.mu.Lock()
	defer h.mu.Unlock()
	h.closeEvents = append(h.closeEvents, fn)
}

// OnError 注册错误事件处理器
func (h *handlerAgent) OnError(fn Event) {
	if fn == nil {
		return
	}
	h.mu.Lock()
	defer h.mu.Unlock()
	h.errorEvents = append(h.errorEvents, fn)
}

// SetLevel 设置日志等级(支持动态切换日志等级)
func (h *handlerAgent) SetLevel(level slog.Level) {
	if h.logLevel.Level() != level {
		h.logLevel.Set(level)
		h.options.Level = level
	}
}

// GetLevel 获取日志等级
func (h *handlerAgent) GetLevel() slog.Level {
	return h.logLevel.Level()
}

// SetCallerSkip 设置日志记录 callerSkip
//   - 默认 3 ( 最小3, 保持与 slog 一致 )
func (h *handlerAgent) SetCallerSkip(skip int) {
	if skip < defaultCallerSkip {
		return
	}
	h.options.CallerSkip = skip
}

// GetCallerSkip 获取日志记录 callerSkip
func (h *handlerAgent) GetCallerSkip() int {
	return h.options.CallerSkip
}

// use 使用中间件
func (h *handlerAgent) use(fns ...Middleware) *handlerAgent {
	h.mu.Lock()
	defer h.mu.Unlock()
	h2 := *h
	if h.middlewares != nil {
		h2.middlewares = slices.Clip(h.middlewares)
	}
	for _, fn := range fns {
		if fn == nil {
			continue
		}
		h2.middlewares = append(h2.middlewares, fn)
	}
	return &h2
}

func (h *handlerAgent) clone() *handlerAgent {
	h.mu.Lock()
	defer h.mu.Unlock()
	h2 := *h
	if h.withAttrs != nil {
		h2.withAttrs = slices.Clip(h.withAttrs)
	}
	if h.middlewares != nil {
		h2.middlewares = slices.Clip(h.middlewares)
	}
	if h.errorEvents != nil {
		h2.errorEvents = slices.Clip(h.errorEvents)
	}
	if h.closeEvents != nil {
		h2.closeEvents = slices.Clip(h.closeEvents)
	}
	return &h2
}

// Sync  同步 Storage缓冲区执行Buffer/Flush操作(仅同步/不关闭)
//   - 具体实现取决于日志Storage存储器
func (h *handlerAgent) Sync() error {
	err := h.storage.Sync()
	if err != nil {
		h.mu.Lock()
		h.lastErrors.append(err)
		h.mu.Unlock()
		if h.errorEvents != nil {
			for _, fn := range h.errorEvents {
				fn(err)
			}
		}
	}
	return err
}

// Close 关闭 Storage (先同步/再关闭), 关闭后将不再接受日志记录
//   - 具体实现取决于日志Storage存储器
func (h *handlerAgent) Close() error {
	err := h.storage.Close()
	if err != nil {
		h.mu.Lock()
		h.lastErrors.append(err)
		h.mu.Unlock()
		if h.errorEvents != nil {
			for _, fn := range h.errorEvents {
				fn(err)
			}
		}
	}
	if h.closeEvents != nil {
		for _, fn := range h.closeEvents {
			fn(err)
		}
	}
	return err
}

// IsClose 日志 Storage 是否已关闭
func (h *handlerAgent) IsClose() bool {
	return h.storage.IsClose()
}

// LastErrors 获取 Handler及Storage 最近的错误信息
func (h *handlerAgent) LastErrors() error {
	h.mu.RLock()
	defer h.mu.RUnlock()
	if h.lastErrors == nil || len(h.lastErrors.errs) == 0 {
		return nil
	}
	return h.lastErrors
}

// -------------------------
// 实现 slog Wrapper 接口
// -------------------------
// log slog.log(...) Wrap日志入口, 支持临时自定义callerSkip
func (h *handlerAgent) log(ctx context.Context, level slog.Level, msg string, args ...any) error {
	if !h._enabled(level) {
		return nil
	}
	var pc uintptr
	if h.options.AddSource {
		// !internal.IgnorePC =>TRUE
		var pcs [1]uintptr
		// skip [runtime.Callers, this function, this function's caller]
		runtime.Callers(h.options.CallerSkip, pcs[:])
		pc = pcs[0]
	}
	record := slog.NewRecord(time.Now(), level, msg, pc)
	if len(args) > 0 {
		record.Add(args...)
	}
	return h._handle(ctx, record)
}

// logAttrs slog.logAttrs(...) Wrap日志入口, 支持临时自定义callerSkip
func (h *handlerAgent) logAttrs(ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) error {
	if !h._enabled(level) {
		return nil
	}
	var pc uintptr
	if h.options.AddSource {
		// !internal.IgnorePC =>TRUE
		var pcs [1]uintptr
		// skip [runtime.Callers, this function, this function's caller]
		runtime.Callers(h.options.CallerSkip, pcs[:])
		pc = pcs[0]
	}
	record := slog.NewRecord(time.Now(), level, msg, pc)
	if len(attrs) > 0 {
		record.AddAttrs(attrs...)
	}
	return h._handle(ctx, record)
}

// Wrap slog.log(...) Wrap日志入口, 支持临时自定义callerSkip
func (h *handlerAgent) Wrap(skip int, ctx context.Context, level slog.Level, msg string, args ...any) error {
	if !h._enabled(level) {
		return nil
	}
	var pc uintptr
	if h.options.AddSource {
		// !internal.IgnorePC =>TRUE
		var pcs [1]uintptr
		// skip [runtime.Callers, this function, this function's caller]
		runtime.Callers(skip, pcs[:])
		pc = pcs[0]
	}
	record := slog.NewRecord(time.Now(), level, msg, pc)
	if len(args) > 0 {
		record.Add(args...)
	}
	return h._handle(ctx, record)
}

// WrapAttrs slog.logAttrs(...) Wrap日志入口, 支持临时自定义callerSkip
func (h *handlerAgent) WrapAttrs(skip int, ctx context.Context, level slog.Level, msg string, attrs ...slog.Attr) error {
	if !h._enabled(level) {
		return nil
	}
	var pc uintptr
	if h.options.AddSource {
		// !internal.IgnorePC =>TRUE
		var pcs [1]uintptr
		// skip [runtime.Callers, this function, this function's caller]
		runtime.Callers(skip, pcs[:])
		pc = pcs[0]
	}
	record := slog.NewRecord(time.Now(), level, msg, pc)
	if len(attrs) > 0 {
		record.AddAttrs(attrs...)
	}
	return h._handle(ctx, record)
}

// -------------------------
// 实现 slog.Handler 接口
// -------------------------

// Enabled 当前日志级别是否开启
func (h *handlerAgent) Enabled(_ context.Context, level slog.Level) bool {
	return level >= h.logLevel.Level() && !h.storage.IsClose()
}
func (h *handlerAgent) _enabled(level slog.Level) bool {
	return level >= h.logLevel.Level() && !h.storage.IsClose()
}

// Handle 处理日志记录，仅在 Enabled() 返回 true 时才会被调用
func (h *handlerAgent) Handle(ctx context.Context, record slog.Record) error {
	if h.options.AddSource && h.options.CallerSkip != 3 {
		// 重写记录的调用栈信息埋点层数, 这里加1层，以保持与sLog默认调用栈一致
		var pcs [1]uintptr
		// skip [runtime.Callers, this function, this function's caller]
		runtime.Callers(h.options.CallerSkip+1, pcs[:])
		record.PC = pcs[0]
	}
	return h._handle(ctx, record)
}
func (h *handlerAgent) _handle(ctx context.Context, record slog.Record) error {
	if len(h.withAttrs) > 0 {
		record.AddAttrs(h.withAttrs...)
	}
	if len(h.middlewares) > 0 {
		for _, fn := range h.middlewares {
			if err := fn(&ctx, &record); err != nil {
				h.mu.Lock()
				h.lastErrors.append(err)
				h.mu.Unlock()
				if h.errorEvents != nil {
					for _, fn := range h.errorEvents {
						fn(err)
					}
				}
				return err
			}
		}
	}
	err := h.handler.Handle(ctx, record)
	if err != nil {
		h.mu.Lock()
		h.lastErrors.append(err)
		h.mu.Unlock()
		if h.errorEvents != nil {
			for _, fn := range h.errorEvents {
				fn(err)
			}
		}
	}
	return err
}

// WithAttrs 从现有的 handler 创建一个新的 handler，并将新增属性附加到新的 handler
//   - Agent 代理了 WithAttrs 以支持中间件,  这里保留原有 Handler, 避免重复 WithAttrs
//   - slog 原生方式预编码了WithAttrs, 导致中间件无法读取到 WithAttrs 数据
//   - 如重复使用 handler.WithAttrs  导致 Attrs 重复追加
//   - If the attrs is empty, WithAttrs returns the receiver.
func (h *handlerAgent) WithAttrs(attrs []slog.Attr) slog.Handler {
	if len(attrs) == 0 {
		return h
	}
	h2 := h.clone()
	h2.withAttrs = append(h2.withAttrs, attrs...)
	return h2
	//return h.handler.WithAttrs(attrs)
}

// WithGroup 从现有的 handler 创建一个新的 handler，并将指定分组附加到新的 handler
//   - If the name is empty, WithGroup returns the receiver.
func (h *handlerAgent) WithGroup(name string) slog.Handler {
	if len(name) == 0 {
		return h
	}
	h2 := h.clone()
	h2.handler = h.handler.WithGroup(name)
	return h2
	//return h.handler.WithGroup(name)
}

// lastErrors 最近10条错误信息
type lastErrors struct {
	errs []error
}

// append 添加错误信息 仅保留最新10条
func (l *lastErrors) append(err error) {
	if err == nil {
		return
	}
	if len(l.errs) >= 10 {
		l.errs = l.errs[1:] // 直接切片，丢弃第一个元素
	}
	l.errs = append(l.errs, err)
}
func (e *lastErrors) Error() string {
	if len(e.errs) == 1 {
		return e.errs[0].Error()
	}
	b := []byte(e.errs[0].Error())
	for _, err := range e.errs[1:] {
		b = append(b, '\n')
		b = append(b, err.Error()...)
	}
	return unsafe.String(&b[0], len(b))
}

func (e *lastErrors) Unwrap() []error {
	return e.errs
}
